/**
*  \file fdmem.c
*
*  \brief    File device emulation.
*
*  \author   Michael J. Hohmann <michael.hohmann@linde-mh.de>
*            Michael Kunkelmann <m.kunkelmann@webergmbh.de>
*
*
*/

/*===============================================[ private includes  ]================================================*/
#include <string.h>
#include "../fdmem/fdmem.h"

/*===============================================[ private defines   ]================================================*/

/*===============================================[ private datatypes ]================================================*/

/*===============================================[ private variables ]================================================*/

/*===============================================[ public variables  ]================================================*/

/*===============================================[ private functions ]================================================*/

static RC fdmem_open_function( struct fd *fd, CH* mode );
static RC fdmem_read_function( struct fd *me, void* data, U32 size );
static RC fdmem_write_function(struct fd *me, void const* data, U32 size );
static RC fdmem_close_function(struct fd *fd, enum fd_close_status close_state );
static RC fdmem_stat_function( struct fd *me, struct fd_stat *stat );

/*====================================================================================================================*/


RC fdmem_initialize( struct fdmem *me, void* data, U32 min, U32 size )
{
   memset( me, 0x00, sizeof(*me) );

   me->fd.open = fdmem_open_function;
   me->fd.close = fdmem_close_function;
   me->fd.read = fdmem_read_function;
   me->fd.write = fdmem_write_function;
   me->fd.stat = fdmem_stat_function;
   me->transmission_status.size_min = min;
   me->transmission_status.size_max = size;
   me->data = data;

   return RC_SUCCESS;
}


/** Open the file device.
*
*  The function fdmem_open_function() opens the file device.
*
*  \param fd Pointer to the file device object. It is not save to pass NULL.
*  \param mode Pointer to the mode object. It is not save to pass NULL.
*
*  \return RC_SUCCESS if device could be opened.
*          RC_ERROR if device could not be opened.
*
*/
static RC fdmem_open_function( struct fd *fd, CH* mode )
{
   struct fdmem *me = (void*) fd;
   me->transmission_status.position=0;

   return RC_SUCCESS;
}


/** Read from the file device.
*
*  The function fdmem_read_function() reads an amount of data from the file device.
*
*  \param fd Pointer to the file device object. It is not save to pass NULL.
*  \param data Pointer to the data to be read out of the file device. It is not save to pass NULL.
*  \param size Amount of data to be read from the file device.
*
*  \return RC_SUCCESS if reading data from the device was successful.
*          RC_ERROR_RANGE if the total size of data could not be read from the file device.
*
*/
static RC fdmem_read_function( struct fd *fd, void* data, U32 size )
{
   struct fdmem *me = (void*) fd;

   if( me->transmission_status.position + size > me->transmission_status.size_max)
   {
      return RC_ERROR_RANGE;
   }
   else
   {
      U8 *d=data;

      while( size-- )
      {
         *d = me->data[ me->transmission_status.position ];
         me->transmission_status.position++;
         d++;
      }
   }

   return RC_SUCCESS;
}


/** Write to file device.
*
*  The function fdmem_write_function() writes the provided amount of data into the file device.
*
*  \param fd Pointer to the file device object. It is not save to pass NULL.
*  \param data Pointer to the data to be written to the file device. It is not save to pass NULL.
*  \param size Amount of data to be written to the file device.
*
*  \return RC_SUCCESS if writing was successful.
*          RC_ERROR_RANGE if the total size of data could not be written to the file device.
*
*/
static RC fdmem_write_function( struct fd *fd, void const* data, U32 size )
{
   struct fdmem *me = (void*) fd;

   if( me->transmission_status.position + size > me->transmission_status.size_max)
   {
      return RC_ERROR_RANGE;
   }
   else
   {
      U8 const *d = data;

      while( size-- )
      {
         me->data[ me->transmission_status.position ] = *d;
         me->transmission_status.position++;
         d++;
      }
   }

   return RC_SUCCESS;
}


/** Close the file device.
*
*  The function fdmem_close_function() closes the file device.
*
*  \param fd Pointer to the file device object. It is not save to pass NULL.
*  \param close_state Status if file can be closed successfully or due to an error.
*
*  \return RC_ERROR if there was a range error. RC_SUCCESS else.
*
*/
static RC fdmem_close_function(struct fd *fd, enum fd_close_status close_state  )
{
   struct fdmem *me = (void*) fd;
   me->transmission_status.position = 0;
   if( me->transmission_status.position < me->transmission_status.size_min )
   {
      return RC_ERROR;
   }


   return RC_SUCCESS;
}


/** File device status extraction.
*
*  The function fdmem_stat_function() reads the status of the file device.
*
*  \param fd Pointer to the file device object. It is not save to pass NULL.
*  \param stat Pointer to the status object. It is not save to pass NULL.
*
*  \return RC_SUCCESS.
*
*/
static RC fdmem_stat_function( struct fd *fd, struct fd_stat *stat )
{
   struct fdmem *me = (void*) fd;
   memcpy( stat, &me->transmission_status, sizeof( struct fd_stat ));
   return RC_SUCCESS;
}

/***********************************************************************************************************************
*                             Copyright 2011 Linde Material Handling. All rights reserved.                             *
***********************************************************************************************************************/
